package com.hzncc.flowable_diboot.payment.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.diboot.core.binding.Binder;
import com.diboot.core.binding.QueryBuilder;
import com.diboot.core.exception.BusinessException;
import com.diboot.core.holder.ThreadLocalHolder;
import com.diboot.core.util.S;
import com.diboot.core.util.V;
import com.diboot.core.vo.Pagination;
import com.diboot.iam.entity.BaseLoginUser;
import com.diboot.iam.util.IamSecurityUtils;
import com.hzncc.flowable_diboot.constans.ContractModelKeyConstants;
import com.hzncc.flowable_diboot.contract.entity.ContractAudit;
import com.hzncc.flowable_diboot.contract.entity.ContractInfo;
import com.hzncc.flowable_diboot.contract.entity.SalesContract;
import com.hzncc.flowable_diboot.contract.service.ContractAuditService;
import com.hzncc.flowable_diboot.contract.service.ContractInfoService;
import com.hzncc.flowable_diboot.contract.service.SalesContractService;
import com.hzncc.flowable_diboot.contract.vo.ContractInfoDetailVO;
import com.hzncc.flowable_diboot.contract.vo.SalesContractListVO;
import com.hzncc.flowable_diboot.entity.SapCustomer;
import com.hzncc.flowable_diboot.entity.invoicemanage.InvoiceRegister;
import com.hzncc.flowable_diboot.entity.refundmanage.RefundRegister;
import com.hzncc.flowable_diboot.enums.BpmDeleteReasonEnum;
import com.hzncc.flowable_diboot.enums.BpmProcessInstanceStatusEnum;
import com.hzncc.flowable_diboot.enums.ContractAuditStatusEnum;
import com.hzncc.flowable_diboot.enums.RegisterTypeEnum;
import com.hzncc.flowable_diboot.payment.dto.PaymentContractDTO;
import com.hzncc.flowable_diboot.payment.entity.OldReceive;
import com.hzncc.flowable_diboot.payment.entity.PaymentContract;
import com.hzncc.flowable_diboot.payment.entity.PaymentRegister;
import com.hzncc.flowable_diboot.payment.entity.SapPaymentContract;
import com.hzncc.flowable_diboot.payment.service.OldReceiveService;
import com.hzncc.flowable_diboot.payment.service.PaymentRegisterService;
import com.hzncc.flowable_diboot.payment.service.SapPaymentContractService;
import com.hzncc.flowable_diboot.payment.vo.*;
import com.hzncc.flowable_diboot.project_contracts.entity.ProjectContractAmount;
import com.hzncc.flowable_diboot.project_contracts.entity.ProjectContractAudit;
import com.hzncc.flowable_diboot.project_contracts.service.ProjectContractAmountService;
import com.hzncc.flowable_diboot.project_contracts.service.ProjectContractAuditService;
import com.hzncc.flowable_diboot.project_contracts.vo.ProjectContractAmountDetailVO;
import com.hzncc.flowable_diboot.project_contracts.vo.ProjectContractAmountListVO;
import com.hzncc.flowable_diboot.project_contracts.vo.ProjectContractAuditDetailVO;
import com.hzncc.flowable_diboot.service.SapCustomerService;
import com.hzncc.flowable_diboot.service.bpm.BpmProcessDefinitionService;
import com.hzncc.flowable_diboot.service.bpm.BpmProcessInstanceService;
import com.hzncc.flowable_diboot.service.bpm.BpmProcessTaskService;
import com.hzncc.flowable_diboot.service.invoicemanage.InvoiceRegisterService;
import com.hzncc.flowable_diboot.service.refundmanage.RefundCertItemService;
import com.hzncc.flowable_diboot.service.refundmanage.RefundCertService;
import com.hzncc.flowable_diboot.vo.bpm.BpmProcessInstanceCreateReqVO;
import com.hzncc.flowable_diboot.vo.bpm.BpmProcessInstanceRespVO;
import com.hzncc.flowable_diboot.vo.bpm.BpmTaskApproveReqVO;
import com.hzncc.flowable_diboot.vo.refundmanage.RefundCertDetailVO;
import com.hzncc.flowable_diboot.vo.refundmanage.RefundContractDetailVO;
import com.hzncc.flowable_diboot.vo.refundmanage.RefundRegisterDetailVO;
import com.hzncc.flowable_diboot.vo.refundmanage.SapRefundContractDetailVO;
import com.sap.conn.jco.JCoException;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.RuntimeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.diboot.core.service.impl.BaseServiceImpl;

import com.hzncc.flowable_diboot.mapper.PaymentContractMapper;
import com.hzncc.flowable_diboot.payment.service.PaymentContractService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;



/**
* 合同收款 相关Service实现类
* @author MyName
* @version 1.0
* @date 2024-10-28
* Copyright © MyCorp
*/
@Slf4j
@Service
public class PaymentContractServiceImpl extends BaseServiceImpl<PaymentContractMapper, PaymentContract> implements PaymentContractService {

    @Resource
    private PaymentRegisterService paymentRegisterService;

    @Resource
    private BpmProcessDefinitionService bpmProcessDefinitionService;

    @Resource
    private BpmProcessInstanceService bpmProcessInstanceService;

    @Resource
    private BpmProcessTaskService bpmProcessTaskService;

    @Resource
    private SalesContractService salesContractService;

    @Resource
    private ContractAuditService contractAuditService;

    @Resource
    private ContractInfoService contractInfoService;

    @Resource
    private SapPaymentContractService sapPaymentContractService;

    @Resource
    private InvoiceRegisterService invoiceRegisterService;

    @Resource
    private ProjectContractAmountService projectContractAmountService;

    @Resource
    private ProjectContractAuditService projectContractAuditService;

    @Resource
    private SapCustomerService sapCustomerService;

    @Resource
    private OldReceiveService oldReceiveService;

    @Resource
    private RefundCertService refundCertService;


    @Override
    public Map<String,List<SapPaymentContractListVO>> getSapPaymentContract(String sapCustomerId) {
        Map<String,List<SapPaymentContractListVO>> result = new HashMap<>();
        LambdaQueryWrapper<SalesContract> salesContractQuery = new LambdaQueryWrapper<>();
        salesContractQuery.eq(SalesContract::getSoldToParty,sapCustomerId).in(SalesContract::getPaymentStatus,1,2)
                .eq(SalesContract::isDeleted,0)
                .eq(SalesContract::getPushStatus, 1); // 只带回推送成功的销售合同
        List<SalesContract> entityList = salesContractService.getEntityList(salesContractQuery);
        List<SalesContractListVO> salesContractListVOS = Binder.convertAndBindRelations(entityList, SalesContractListVO.class);
        List<SapPaymentContractListVO> sapInvoicedPaymentContractListVOS = new ArrayList<>();
        List<SapPaymentContractListVO> sapNoInvoicedPaymentContractListVOS = new ArrayList<>();
        for (SalesContractListVO salesContractListVO : salesContractListVOS){
            SapPaymentContractListVO sapPaymentContractListVO = new SapPaymentContractDetailVO();
            sapPaymentContractListVO.setContractCode(salesContractListVO.getOrderCode()); // 采购订单编号
            sapPaymentContractListVO.setSapContractCode(salesContractListVO.getSapCode()); // sap合同号
            sapPaymentContractListVO.setTotalAmount(new BigDecimal(StringUtils.isNotEmpty(salesContractListVO.getFixedDiscountAmount())?salesContractListVO.getFixedDiscountAmount():"0")); // 合同总金额
            sapPaymentContractListVO.setReceivedAmount(new BigDecimal(StringUtils.isNotEmpty(salesContractListVO.getAmountReceived())?salesContractListVO.getAmountReceived():"0")); // 已收款金额
            if (StringUtils.isNotEmpty(salesContractListVO.getAmountNotReceived())){
                sapPaymentContractListVO.setUnpaidAmount(new BigDecimal(salesContractListVO.getAmountNotReceived()));
            }else{
                sapPaymentContractListVO.setUnpaidAmount(sapPaymentContractListVO.getTotalAmount().subtract(sapPaymentContractListVO.getReceivedAmount()));
            }
            sapPaymentContractListVO.setInvoicedTime(salesContractListVO.getOrderDate()); // 开票日期
            sapPaymentContractListVO.setSalesEmployeeId(salesContractListVO.getSalesEmployee());
            sapPaymentContractListVO.setSalesEmployeeName(salesContractListVO.getSalesEmployeeLabel());
            sapPaymentContractListVO.setSalesArea(salesContractListVO.getSalesTerritory());
            if (StringUtils.isEmpty(salesContractListVO.getProjectContractId())){
                sapPaymentContractListVO.setReviewCategory("0");
            }else {
                sapPaymentContractListVO.setReviewCategory("1");
            }
            LambdaQueryWrapper<InvoiceRegister> invoiceRegisterQuery = new LambdaQueryWrapper<>();
            invoiceRegisterQuery.eq(InvoiceRegister::getSapContractCode,salesContractListVO.getSapCode()).in(InvoiceRegister::getRegisterType, RegisterTypeEnum.normal.getCode(),RegisterTypeEnum.abnormal.getCode());
            List<InvoiceRegister> invoiceRegisterList = invoiceRegisterService.getEntityList(invoiceRegisterQuery);
            if (CollectionUtils.isEmpty(invoiceRegisterList)){
                sapPaymentContractListVO.setInvoicedAmount(new BigDecimal(0));
                sapPaymentContractListVO.setInvoicedTime(null); // 开票日期
                sapNoInvoicedPaymentContractListVOS.add(sapPaymentContractListVO);
            }else {
                BigDecimal invoiceAmountTotal = invoiceRegisterList.stream().map(InvoiceRegister::getInvoiceAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                if (invoiceAmountTotal.compareTo(new BigDecimal(0))<=0){
                    sapPaymentContractListVO.setInvoicedAmount(new BigDecimal(0));
                }
                sapPaymentContractListVO.setInvoicedAmount(invoiceAmountTotal);
                sapInvoicedPaymentContractListVOS.add(sapPaymentContractListVO);
            }
        }
        result.put("invoiced",sapInvoicedPaymentContractListVOS);
        result.put("noInvoiced",sapNoInvoicedPaymentContractListVOS);
        return result;
    }

//    @Override
//    public OldReceiveListVO getOldReceive(String sapCustomerId) {
//        //查询客户的老应收
//        SapCustomer sapCustomer = sapCustomerService.getEntity(sapCustomerId);
//        String sapNo = sapCustomer.getSapNo();
//        String companyCode = sapCustomer.getCompanyCode();
//
//        LambdaQueryWrapper<OldReceive> oldReceiveQuery = new LambdaQueryWrapper<>();
//        oldReceiveQuery.eq(OldReceive::getCompanyCode,companyCode).eq(OldReceive::getSapNo,sapNo).eq(OldReceive::isDeleted,0);
//        ThreadLocalHolder.setIgnoreInterceptor();
//        OldReceive oldReceive = oldReceiveService.getSingleEntity(oldReceiveQuery);
//        OldReceiveListVO oldReceiveListVO = new OldReceiveListVO();
//        if (ObjectUtils.isNotEmpty(oldReceive)){
//            oldReceiveListVO = Binder.convertAndBindRelations(oldReceive, OldReceiveListVO.class);
//        }else {
//            oldReceiveListVO.setReceivableAmount(new BigDecimal(0)).setReceivedAmount(new BigDecimal(0)).setUnreceivedAmount(new BigDecimal(0));
//        }
//        return oldReceiveListVO;
//    }

    public List<SapPaymentContractListVO> getOldReceive(String customerId){
        LambdaQueryWrapper<ProjectContractAudit> projectContractAuditQuery = new LambdaQueryWrapper<>();
        projectContractAuditQuery.eq(ProjectContractAudit::getCustomerId,customerId)
                .eq(ProjectContractAudit::getCate,"2");
        List<ProjectContractAudit> projectContractAuditList = projectContractAuditService.getEntityList(projectContractAuditQuery);
        List<ProjectContractAuditDetailVO> projectContractAuditDetailVOS = Binder.convertAndBindRelations(projectContractAuditList, ProjectContractAuditDetailVO.class);
        List<SapPaymentContractListVO> sapPaymentContractListVOS = new ArrayList<>();
        for (ProjectContractAuditDetailVO projectContractAuditDetailVO : projectContractAuditDetailVOS){
            SapPaymentContractListVO sapPaymentContractListVO = new SapPaymentContractDetailVO();
            sapPaymentContractListVO.setContractCode(projectContractAuditDetailVO.getContractCode()); // 采购订单编号
            sapPaymentContractListVO.setSapContractCode(null); // sap合同号
            sapPaymentContractListVO.setTotalAmount(projectContractAuditDetailVO.getProjectContractAmount().getContractSalesTotalAmount()); // 合同总金额
            sapPaymentContractListVO.setInvoicedAmount(projectContractAuditDetailVO.getProjectContractAmount().getContractSalesTotalAmount()); //开票金额
            sapPaymentContractListVO.setReceivedAmount(projectContractAuditDetailVO.getProjectContractAmount().getCollectedAmount()); // 已收款金额
            sapPaymentContractListVO.setUnpaidAmount(projectContractAuditDetailVO.getProjectContractAmount().getUncollectedAmount());
            sapPaymentContractListVO.setInvoicedTime(null); // 开票日期
            sapPaymentContractListVO.setSalesEmployeeId(projectContractAuditDetailVO.getSaler());
            sapPaymentContractListVO.setSalesEmployeeName(projectContractAuditDetailVO.getSalerName());
            sapPaymentContractListVO.setSalesArea(projectContractAuditDetailVO.getSalesTerritory());
            sapPaymentContractListVO.setReviewCategory("1");
            sapPaymentContractListVO.setOldReceivableId(projectContractAuditDetailVO.getId()); // 老应收id
            sapPaymentContractListVOS.add(sapPaymentContractListVO);
        }
        return sapPaymentContractListVOS;
    }

    @Override
    public List<PaymentContractListVO> getPaymentContractList(PaymentContractDTO queryDto, Pagination pagination) {
        if (StringUtils.isNotEmpty(queryDto.getSapCustomerName())){
            LambdaQueryWrapper<SapCustomer> sapCustomerQuery = new LambdaQueryWrapper<>();
            sapCustomerQuery.like(SapCustomer::getName, "%" + queryDto.getSapCustomerName()+ "%");
            List<SapCustomer> entityList = sapCustomerService.getEntityList(sapCustomerQuery);
            List<String> collect = entityList.stream().map(SapCustomer::getId).collect(Collectors.toList());
            queryDto.setSapCustomerIds(collect);
            queryDto.setSapCustomerName(null);
        }
        QueryWrapper<PaymentContract> queryWrapper = QueryBuilder.toQueryWrapper(queryDto);
        if (pagination != null && V.isEmpty(pagination.getOrderBy())) {
            pagination.setOrderBy(Pagination.ORDER_BY_ID_DESC);
        }

        return this.getViewObjectList(queryWrapper, pagination, PaymentContractListVO.class);
    }

    @Override
    @Transactional
    public Boolean createPaymentContract(PaymentContractDetailVO paymentContract) {
        if (StringUtils.isEmpty(paymentContract.getPaymentRegisterId())){
            throw new BusinessException("回款登记不存在");
        }
        PaymentRegister paymentRegister = paymentRegisterService.getEntity(paymentContract.getPaymentRegisterId());
        if (ObjectUtils.isEmpty(paymentRegister)){
            throw new BusinessException("回款登记不存在");
        }
        BigDecimal unclaimedAmount = paymentRegister.getUnclaimedAmount();
        BigDecimal currentReceivedAmount = paymentContract.getCurrentReceivedAmount();
        if (unclaimedAmount.compareTo(currentReceivedAmount)<0){
            throw new BusinessException("当前回款金额大于回款登记未收款金额,无法进行合同收款");
        }
        paymentContract.setProcessState("1");
        if (ObjectUtils.isNotEmpty(paymentContract.getAdvanceAmount())){
            paymentContract.setCurrentReceivedAmount(paymentContract.getAdvanceAmount());
        }
        this.createEntity(paymentContract);
        String sapCustomerId = paymentContract.getSapCustomer();
        String sapCustomerCode = paymentContract.getSapCustomerCode();
        paymentRegister.setSapCustomerId(sapCustomerId).setCustomerCode(sapCustomerCode);
        paymentRegisterService.updateEntity(paymentRegister);
        List<SapPaymentContractDetailVO> sapPaymentContractDetailVOList = paymentContract.getSapPaymentContractList();
        Map<String,Object> variables = new HashMap<>();
        variables.put("hasSapPayment","0");
        if (!CollectionUtils.isEmpty(sapPaymentContractDetailVOList)){
            sapPaymentContractDetailVOList = sapPaymentContractDetailVOList.stream().filter(item-> item.getCurrentCollectionAmount().compareTo(new BigDecimal(0))>0).collect(Collectors.toList());
            sapPaymentContractDetailVOList = sapPaymentContractDetailVOList.stream().peek(item->{
                item.setPaymentContractId(paymentContract.getId());
                item.setReceivedAmount(item.getReceivedAmount().add(item.getCurrentCollectionAmount()));
                item.setUnpaidAmount(item.getTotalAmount().subtract(item.getReceivedAmount()));
            }).collect(Collectors.toList());
            sapPaymentContractService.createEntities(sapPaymentContractDetailVOList);
            variables.put("hasSapPayment","1");
        }
        String category = paymentRegister.getCategory();
        String externalReceived = paymentContract.getExternalReceived();
        String paymentContractCategory = paymentContract.getPaymentContractCategory();
        variables.put("paymentCategory",category);
        variables.put("externalReceived",externalReceived);
        variables.put("paymentContractCategory",paymentContractCategory);
        String instanceId = this.createContractProcessInstance(ContractModelKeyConstants.PAYMENT_CONTRACT_SUBMIT, paymentContract.getId(),variables);
        paymentContract.setInstanceId(instanceId);
        this.updateEntity(paymentContract);
        bpmProcessTaskService.commitUserTask(instanceId);
        return true;
    }

    @Override
    @Transactional
    public Boolean updatePaymentContract(PaymentContractDetailVO paymentContract) {
        if (StringUtils.isEmpty(paymentContract.getPaymentRegisterId())){
            throw new BusinessException("回款登记不存在");
        }
        PaymentRegister paymentRegister = paymentRegisterService.getEntity(paymentContract.getPaymentRegisterId());
        if (ObjectUtils.isEmpty(paymentRegister)){
            throw new BusinessException("回款登记不存在");
        }
        BigDecimal unclaimedAmount = paymentRegister.getUnclaimedAmount();
        BigDecimal currentReceivedAmount = paymentContract.getCurrentReceivedAmount();
        if (unclaimedAmount.compareTo(currentReceivedAmount)<0){
            throw new BusinessException("当前回款金额大于回款登记未收款金额,无法进行合同收款");
        }
        paymentContract.setProcessState("1");
        if (ObjectUtils.isNotEmpty(paymentContract.getAdvanceAmount())){
            paymentContract.setCurrentReceivedAmount(paymentContract.getAdvanceAmount());
        }
        this.updateEntity(paymentContract);
        String sapCustomerId = paymentContract.getSapCustomer();
        String sapCustomerCode = paymentContract.getSapCustomerCode();
        paymentRegister.setSapCustomerId(sapCustomerId).setCustomerCode(sapCustomerCode);
        paymentRegisterService.updateEntity(paymentRegister);
        LambdaQueryWrapper<SapPaymentContract> sapPaymentContractQuery = new LambdaQueryWrapper<>();
        sapPaymentContractQuery.eq(SapPaymentContract::getPaymentContractId,paymentContract.getId());
        sapPaymentContractService.deleteEntities(sapPaymentContractQuery);
        List<SapPaymentContractDetailVO> sapPaymentContractDetailVOList = paymentContract.getSapPaymentContractList();
        Map<String,Object> variables = new HashMap<>();
        variables.put("hasSapPayment","0");
        if (!CollectionUtils.isEmpty(sapPaymentContractDetailVOList)){
            sapPaymentContractDetailVOList = sapPaymentContractDetailVOList.stream().peek(item->{
                item.setId(null);
                item.setPaymentContractId(paymentContract.getId());
                item.setReceivedAmount(item.getReceivedAmount().add(item.getCurrentCollectionAmount()));
                item.setUnpaidAmount(item.getTotalAmount().subtract(item.getReceivedAmount()));
            }).collect(Collectors.toList());
            sapPaymentContractService.createEntities(sapPaymentContractDetailVOList);
            variables.put("hasSapPayment","1");
        }
        String category = paymentRegister.getCategory();
        String externalReceived = paymentContract.getExternalReceived();
        String paymentContractCategory = paymentContract.getPaymentContractCategory();
        variables.put("paymentCategory",category);
        variables.put("externalReceived",externalReceived);
        variables.put("paymentContractCategory",paymentContractCategory);
        variables.put("approve","1");
        BpmTaskApproveReqVO approveReqVO = new BpmTaskApproveReqVO();
        approveReqVO.setId(paymentContract.getTaskId());
        approveReqVO.setReason("审批通过");
        approveReqVO.setVariables(variables);
        bpmProcessTaskService.approveTask(approveReqVO);
        this.updateEntity(paymentContract);
        return true;
    }

    @Override
    @Transactional
    public Boolean revokePaymentRegister(String id) throws JCoException {
        ThreadLocalHolder.setIgnoreInterceptor();
        PaymentRegisterDetailVO paymentRegisterDetailVO = paymentRegisterService.getViewObject(id, PaymentRegisterDetailVO.class);
        if ("1".equals(paymentRegisterDetailVO.getCerted())){
            // 退款凭证
            RefundRegisterDetailVO refundRegisterDetailVO = this.genRefundRegisterDetailVO(paymentRegisterDetailVO);
            RefundCertDetailVO refundCertDetailVO = refundCertService.genRefundCert(refundRegisterDetailVO);
            refundCertService.createRefundCert(refundCertDetailVO,true);
            //修改回款登记生成凭证状态
            paymentRegisterDetailVO.setCerted("0");
            paymentRegisterService.updateEntity(paymentRegisterDetailVO);
        }
        List<PaymentContractDetailVO> paymentContractDetailVOS = paymentRegisterDetailVO.getPaymentContractDetailVOS();
        if (!CollectionUtils.isEmpty(paymentContractDetailVOS)){
            for (PaymentContractDetailVO paymentContractDetailVO : paymentContractDetailVOS){
                Boolean result = this.revokePaymentContract(paymentContractDetailVO.getId());
                if (!result){
                    throw new BusinessException("作废回款失败");
                }
                this.updatePaymentContractStatus(paymentContractDetailVO.getId(),"6");
            }
        }
        return true;
    }

    @Override
    @Transactional
    public Boolean cancelPaymentRegister(String id){
        Map<String,Object> variables = new HashMap<>();
        variables.put("paymentRegisterId",id);
        this.createContractProcessInstance(ContractModelKeyConstants.PAYMENT_REGISTER_CANCEL, id,variables);
        // 修改回款登记状态为审批中
        paymentRegisterService.lambdaUpdate()
                .set(PaymentRegister::getStatus, BpmProcessInstanceStatusEnum.RUNNING.getStatus().toString())
                .eq(PaymentRegister::getId, id)
                .update();
        return true;
    }

    @Override
    @Transactional
    public Boolean revokePaymentContract(String id) {
        ThreadLocalHolder.setIgnoreInterceptor();
        PaymentContractDetailVO paymentContract = this.getViewObject(id, PaymentContractDetailVO.class);
        String instanceId = paymentContract.getInstanceId();
        if (StringUtils.isNotEmpty(instanceId)){
            BpmProcessInstanceRespVO bpmProcessInstance = bpmProcessInstanceService.getBpmProcessInstance(instanceId);
            if (S.equals(bpmProcessInstance.getProcessDefinition().getKey(),ContractModelKeyConstants.PAYMENT_CONTRACT_CANCEL)){ // 作废合同收款撤销不用回调数据
                paymentContract.setProcessState(BpmProcessInstanceStatusEnum.APPROVE.getStatus().toString()); // 状态回滚为审批通过便于后续操作
                this.updateEntity(paymentContract);
                return true;
            }else{
                bpmProcessInstanceService.cancelProcessInstance(instanceId,"撤销合同收款");
            }
        }
        // 标记合同收款为撤销
        paymentContract.setWasted(1); // 撤销
        paymentContract.setProcessState(BpmProcessInstanceStatusEnum.CANCEL.getStatus().toString());
        this.updateEntity(paymentContract);
        //撤销回款登记金额
        ThreadLocalHolder.setIgnoreInterceptor();
        PaymentRegister paymentRegister = paymentRegisterService.getEntity(paymentContract.getPaymentRegisterId());
        BigDecimal receivedAmount = paymentRegister.getReceivedAmount();
        BigDecimal unclaimedAmount = paymentRegister.getUnclaimedAmount();
        BigDecimal currentReceivedAmount = paymentContract.getCurrentReceivedAmount();
        if (ObjectUtils.isNotEmpty(receivedAmount)&&ObjectUtils.isNotEmpty(unclaimedAmount)&&ObjectUtils.isNotEmpty(currentReceivedAmount)){
            receivedAmount = receivedAmount.subtract(currentReceivedAmount);
            unclaimedAmount = unclaimedAmount.add(currentReceivedAmount);
            String paymentStatus = "10";
            if (receivedAmount.compareTo(new BigDecimal(0))>0&&unclaimedAmount.compareTo(new BigDecimal(0))>0){
                paymentStatus = "20";
            }else if (unclaimedAmount.compareTo(new BigDecimal(0))<=0){
                paymentStatus = "30";
            }
            LambdaUpdateWrapper<PaymentRegister> paymentRegisterUpdate = new LambdaUpdateWrapper<>();
            paymentRegisterUpdate.set(PaymentRegister::getReceivedAmount,receivedAmount)
                    .set(PaymentRegister::getUnclaimedAmount,unclaimedAmount)
                    .set(PaymentRegister::getStatus,paymentStatus)
                    .set(PaymentRegister::getLocked,1).eq(PaymentRegister::getId,paymentContract.getPaymentRegisterId());
            paymentRegisterService.updateEntity(paymentRegisterUpdate);
        }
        //如果是老应收，更新老应收回款金额
//        if ("30".equals(paymentContract.getPaymentContractCategory())){
//            ThreadLocalHolder.setIgnoreInterceptor();
//            SapCustomer sapCustomer = sapCustomerService.getEntity(paymentContract.getSapCustomer());
//            String sapNo = sapCustomer.getSapNo();
//            String companyCode = sapCustomer.getCompanyCode();
//            LambdaQueryWrapper<OldReceive> oldReceiveQuery = new LambdaQueryWrapper<>();
//            oldReceiveQuery.eq(OldReceive::getCompanyCode,companyCode).eq(OldReceive::getSapNo,sapNo).eq(OldReceive::isDeleted,0);
//            ThreadLocalHolder.setIgnoreInterceptor();
//            OldReceive oldReceive = oldReceiveService.getSingleEntity(oldReceiveQuery);
//            oldReceive.setReceivedAmount(oldReceive.getReceivedAmount().subtract(paymentContract.getContractReceivedAmount()));
//            oldReceive.setUnreceivedAmount(oldReceive.getReceivableAmount().subtract(oldReceive.getReceivedAmount()));
//            ThreadLocalHolder.setIgnoreInterceptor();
//            oldReceiveService.updateEntity(oldReceive);
//        }
        List<SapPaymentContractDetailVO> sapPaymentContractList = paymentContract.getSapPaymentContractList();
        if (!CollectionUtils.isEmpty(sapPaymentContractList)){
            //撤销系统合同金额
            Map<String, BigDecimal> currentReceivedMap = sapPaymentContractList.stream()
                    .collect(Collectors.groupingBy(item ->
                                    item.getContractCode()+"#"+item.getReviewCategory(),
                            Collectors.mapping(SapPaymentContractDetailVO::getCurrentCollectionAmount,Collectors.reducing(BigDecimal.ZERO,BigDecimal::add))
                    ));
            for (Map.Entry<String,BigDecimal> entry: currentReceivedMap.entrySet()){
                String contractCodeAndReviewCategory = entry.getKey();
                String[] split = contractCodeAndReviewCategory.split("#");
                String contractCode = split[0];
                String reviewCategory = split[1];
                BigDecimal currentReceived = entry.getValue();
                if ("0".equals(reviewCategory)){
                    LambdaQueryWrapper<ContractAudit> contractAuditQuery = new LambdaQueryWrapper<>();
                    contractAuditQuery.eq(ContractAudit::getContractCode,contractCode).ne(ContractAudit::getContractStatus, ContractAuditStatusEnum.HISTORY);
                    ThreadLocalHolder.setIgnoreInterceptor();
                    ContractAudit contractAudit = contractAuditService.getSingleEntity(contractAuditQuery);
                    String contractAuditId = contractAudit.getId();
                    LambdaQueryWrapper<ContractInfo> contractInfoQuery = new LambdaQueryWrapper<>();
                    contractInfoQuery.eq(ContractInfo::getContractAuditId,contractAuditId).eq(ContractInfo::isDeleted,0);
                    ThreadLocalHolder.setIgnoreInterceptor();
                    ContractInfo contractInfo = contractInfoService.getSingleEntity(contractInfoQuery);
                    LambdaUpdateWrapper<ContractInfo> contractInfoUpdate = new LambdaUpdateWrapper<>();
                    contractInfoUpdate.set(ContractInfo::getReceivedAmount,contractInfo.getReceivedAmount().subtract(currentReceived))
                            .set(ContractInfo::getOutstandingAmount,contractInfo.getTotalAmount().subtract(contractInfo.getReceivedAmount().subtract(currentReceived)))
                            .eq(ContractInfo::getContractAuditId,contractAuditId);
                    contractInfoService.updateEntity(contractInfoUpdate);
                }else if ("1".equals(reviewCategory)){
                    LambdaQueryWrapper<ProjectContractAudit> projectContractAuditQuery = new LambdaQueryWrapper<>();
                    projectContractAuditQuery.eq(ProjectContractAudit::getContractCode,contractCode).ne(ProjectContractAudit::getContractStatus,ContractAuditStatusEnum.HISTORY)
                            .ne(ProjectContractAudit::getCate,2); // 老应收类型单独处理
                    ThreadLocalHolder.setIgnoreInterceptor();
                    ProjectContractAudit projectContractAudit = projectContractAuditService.getSingleEntity(projectContractAuditQuery);
                    if (projectContractAudit  == null) {
                        continue;
                    }
                    String contractAuditId = projectContractAudit.getId();
                    LambdaQueryWrapper<ProjectContractAmount> projectContractAmountQuery = new LambdaQueryWrapper<>();
                    projectContractAmountQuery.eq(ProjectContractAmount::getContractId,contractAuditId).eq(ProjectContractAmount::isDeleted,0);
                    ThreadLocalHolder.setIgnoreInterceptor();
                    ProjectContractAmount projectContractAmount = projectContractAmountService.getSingleEntity(projectContractAmountQuery);
                    LambdaUpdateWrapper<ProjectContractAmount> projectContractAmountUpdate = new LambdaUpdateWrapper<>();
                    projectContractAmountUpdate.set(ProjectContractAmount::getCollectedAmount,projectContractAmount.getCollectedAmount().subtract(currentReceived))
                            .set(ProjectContractAmount::getUncollectedAmount,projectContractAmount.getContractSalesTotalAmount().subtract(projectContractAmount.getCollectedAmount().subtract(currentReceived)))
                            .eq(ProjectContractAmount::getContractId,contractAuditId);
                    projectContractAmountService.updateEntity(projectContractAmountUpdate);
                }

            }
            //撤销销售合同金额
            for (SapPaymentContractDetailVO sapPaymentContractDetailVO : sapPaymentContractList){
                String sapContractCode = sapPaymentContractDetailVO.getSapContractCode();
                if (S.isBlank(sapContractCode)) { // 老应收
                    withdrawOldReceivables(sapPaymentContractDetailVO);
                    continue;
                }
                LambdaQueryWrapper<SalesContract> salesContractQuery = new LambdaQueryWrapper<>();
                salesContractQuery.eq(SalesContract::getSapCode,sapContractCode).eq(SalesContract::isDeleted,0);
                ThreadLocalHolder.setIgnoreInterceptor();
                SalesContract salesContract = salesContractService.getSingleEntity(salesContractQuery);
                BigDecimal amountReceived = StringUtils.isNotEmpty(salesContract.getAmountReceived())?new BigDecimal(salesContract.getAmountReceived()):new BigDecimal(0);
                BigDecimal amountNotReceived = StringUtils.isNotEmpty(salesContract.getAmountNotReceived())?new BigDecimal(salesContract.getAmountNotReceived()):new BigDecimal(0);
                BigDecimal currentCollectionAmount = sapPaymentContractDetailVO.getCurrentCollectionAmount();
                if (ObjectUtils.isNotEmpty(amountReceived)&&ObjectUtils.isNotEmpty(amountNotReceived)&&ObjectUtils.isNotEmpty(currentCollectionAmount)){
                    amountReceived = amountReceived.subtract(currentCollectionAmount);
                    amountNotReceived = amountNotReceived.add(currentCollectionAmount);
                    String paymentStatus = "1";
                    if (amountReceived.compareTo(new BigDecimal(0))>0&&amountNotReceived.compareTo(new BigDecimal(0))>0){
                        paymentStatus = "2";
                    }else if (amountNotReceived.compareTo(new BigDecimal(0))<=0){
                        paymentStatus = "3";
                    }
                    LambdaUpdateWrapper<SalesContract> salesContractUpdate = new LambdaUpdateWrapper<>();
                    salesContractUpdate.set(SalesContract::getAmountReceived,amountReceived)
                            .set(SalesContract::getAmountNotReceived,amountNotReceived)
                            .set(SalesContract::getPaymentStatus,paymentStatus)
                            .eq(SalesContract::getSapCode,sapPaymentContractDetailVO.getSapContractCode()).eq(SalesContract::isDeleted,0);
                    salesContractService.updateEntity(salesContractUpdate);
                    sapPaymentContractDetailVO.setReceivedAmount(amountReceived).setUnpaidAmount(amountNotReceived);
                    sapPaymentContractService.updateEntity(sapPaymentContractDetailVO);
                }
            }
            //撤销系统合同状态
            Map<String, BigDecimal> received = sapPaymentContractList.stream()
                    .collect(Collectors.groupingBy(item ->
                                    item.getContractCode()+"#"+item.getReviewCategory(),
                            Collectors.mapping(SapPaymentContractDetailVO::getReceivedAmount,Collectors.reducing(BigDecimal.ZERO,BigDecimal::add))
                    ));
            for (Map.Entry<String,BigDecimal> entry: received.entrySet()){
                String contractCodeAndReviewCategory = entry.getKey();
                String[] split = contractCodeAndReviewCategory.split("#");
                String contractCode = split[0];
                String reviewCategory = split[1];
                if ("0".equals(reviewCategory)){
                    LambdaUpdateWrapper<ContractAudit> contractAuditUpdate = new LambdaUpdateWrapper<>();
                    contractAuditUpdate.set(ContractAudit::getContractStatus, ContractAuditStatusEnum.DONE.getCode())
                            .eq(ContractAudit::getContractCode,contractCode).ne(ContractAudit::getContractStatus, ContractAuditStatusEnum.HISTORY.getCode());
                    contractAuditService.updateEntity(contractAuditUpdate);
                } else if ("1".equals(reviewCategory)) {
                    LambdaUpdateWrapper<ProjectContractAudit> projectContractAuditUpdate = new LambdaUpdateWrapper<>();
                    projectContractAuditUpdate.set(ProjectContractAudit::getContractStatus, ContractAuditStatusEnum.DONE.getCode())
                            .eq(ProjectContractAudit::getContractCode,contractCode).ne(ProjectContractAudit::getContractStatus, ContractAuditStatusEnum.HISTORY.getCode());
                    contractAuditService.updateEntity(projectContractAuditUpdate);
                }
            }
        }
        return true;
    }

    /**
     * 撤销老应收金额
     *
     * @param sapPaymentContractDetailVO 撤销数据
     * @author 陈广煜
     * @date 2025-04-01
     */
    private void withdrawOldReceivables(SapPaymentContractDetailVO sapPaymentContractDetailVO) {
        String oldReceivableId = sapPaymentContractDetailVO.getOldReceivableId();
        LambdaQueryWrapper<ProjectContractAmount> projectContractAmountQuery = new LambdaQueryWrapper<>();
        projectContractAmountQuery.eq(ProjectContractAmount::getContractId,oldReceivableId);
        ProjectContractAmount amount = projectContractAmountService.getSingleEntity(projectContractAmountQuery);
        amount.setCollectedAmount(amount.getCollectedAmount().subtract(sapPaymentContractDetailVO.getCurrentCollectionAmount())); // 已收款金额减少
        amount.setUncollectedAmount(amount.getUncollectedAmount().add(sapPaymentContractDetailVO.getCurrentCollectionAmount())); // 未收款金额增加
        projectContractAmountService.updateEntity(amount);
    }

    @Override
    public Boolean cancelPaymentContract(String id) {
        Map<String,Object> variables = new HashMap<>();
        variables.put("paymentContractId",id);
        String instanceId = this.createContractProcessInstance(ContractModelKeyConstants.PAYMENT_CONTRACT_CANCEL, id, variables);
        // 修改合同收款状态
        this.lambdaUpdate()
                .set(PaymentContract::getProcessState, BpmProcessInstanceStatusEnum.RUNNING.getStatus().toString())
                .set(PaymentContract::getInstanceId,instanceId)
                .eq(PaymentContract::getId,id)
                .update();
        return true;
    }

    @Override
    @Transactional
    public Boolean updatePaymentContractStatus(String id, String status) {
        LambdaUpdateWrapper<PaymentContract> paymentContractUpdate = new LambdaUpdateWrapper<>();
        paymentContractUpdate.set(PaymentContract::getProcessState,status).eq(PaymentContract::getId,id);
        return this.update(paymentContractUpdate);
    }

    public String createContractProcessInstance(String modelKey, String businessKey,Map<String,Object> variables) {
        String processDefinitionId = bpmProcessDefinitionService.getBpmProcessDefinitionIdByKey(modelKey);
        BpmProcessInstanceCreateReqVO bpmProcessInstanceCreateReqVO = new BpmProcessInstanceCreateReqVO();
        bpmProcessInstanceCreateReqVO.setProcessDefinitionId(processDefinitionId).setBusinessKey(businessKey).setVariables(variables);
        return bpmProcessInstanceService.createProcessInstance(bpmProcessInstanceCreateReqVO);
    }

    private RefundRegisterDetailVO genRefundRegisterDetailVO(PaymentRegisterDetailVO paymentRegisterDetailVO){
        RefundRegisterDetailVO refundRegisterDetailVO = new RefundRegisterDetailVO();
        refundRegisterDetailVO.setCustomerId(paymentRegisterDetailVO.getSapCustomerId())
                .setSapCustomerId(paymentRegisterDetailVO.getSapCustomerId())
                .setCustomerCode(paymentRegisterDetailVO.getCustomerCode())
                .setRefundAmount(paymentRegisterDetailVO.getPaymentAmount())
                .setRefundTime(LocalDateTime.now())
                .setReturnAmount(paymentRegisterDetailVO.getReceivedAmount())
                .setNoReturnAmount(refundRegisterDetailVO.getRefundAmount().subtract(refundRegisterDetailVO.getReturnAmount()))
                .setRefundType(paymentRegisterDetailVO.getType())
                .setBankName(paymentRegisterDetailVO.getBankName())
                .setPaymentItem(paymentRegisterDetailVO.getPaymentItem())
                .setBillNum(paymentRegisterDetailVO.getBillNum())
                .setCertType(paymentRegisterDetailVO.getCertType())
                .setPaymentItem(paymentRegisterDetailVO.getPaymentItem());
        List<PaymentContractDetailVO> paymentContractDetailVOS = paymentRegisterDetailVO.getPaymentContractDetailVOS();
        List<RefundContractDetailVO> refundContractDetailVOS = new ArrayList<>();
        ThreadLocalHolder.setIgnoreInterceptor();
        Binder.bindRelations(paymentContractDetailVOS);
        for (PaymentContractDetailVO paymentContractDetailVO : paymentContractDetailVOS){
            RefundContractDetailVO refundContractDetailVO = new RefundContractDetailVO();
            refundContractDetailVO.setCostCenterLabel(paymentContractDetailVO.getCostCenterLabel())
                    .setSalerLabel(paymentContractDetailVO.getSalerLabel())
                    .setSalesAreaLabel(paymentContractDetailVO.getSalesAreaLabel())
                    .setSapCustomerCode(paymentContractDetailVO.getSapCustomerCode())
                    .setSapCustomerName(paymentContractDetailVO.getSapCustomerName())
                    .setCostCenter(paymentContractDetailVO.getCostCenter())
                    .setSaler(paymentContractDetailVO.getSaler())
                    .setSalesArea(paymentContractDetailVO.getSalesArea())
                    .setSapCustomerId(paymentContractDetailVO.getSapCustomer())
                    .setCurrentRefundAmount(paymentContractDetailVO.getCurrentReceivedAmount());
            refundContractDetailVOS.add(refundContractDetailVO);
            List<SapPaymentContractDetailVO> sapPaymentContractList = paymentContractDetailVO.getSapPaymentContractList();
            if (sapPaymentContractList == null) { // 外部收款
                continue;
            }
            List<SapRefundContractDetailVO> sapRefundContractList = new ArrayList<>();
            for (SapPaymentContractDetailVO sapPaymentContractDetailVO : sapPaymentContractList){
                SapRefundContractDetailVO sapRefundContractDetailVO = new SapRefundContractDetailVO();
                sapRefundContractDetailVO.setContractCode(sapPaymentContractDetailVO.getContractCode());
                sapRefundContractDetailVO.setCurrentRefundAmount(sapPaymentContractDetailVO.getCurrentCollectionAmount()); // 退款金额
                sapRefundContractList.add(sapRefundContractDetailVO);
            }
            refundContractDetailVO.setSapRefundContractList(sapRefundContractList);
        }
        refundRegisterDetailVO.setRefundContractDetailVOS(refundContractDetailVOS);
        return refundRegisterDetailVO;

    }

    @Override
    public boolean deleteCheck(Set<String> ids) {
        List<PaymentRegister> registers = paymentRegisterService.getEntityListByIds(new ArrayList(ids));
        for (PaymentRegister register : registers) {
            if (!NumberUtil.equals(register.getReceivedAmount(),BigDecimal.ZERO)){
                return false;
            }
        }
        return true;
    }

}